<?php
/**
 * Defines Kodform_Element class
 *
 *
 * @copyright 	Copyright (c) 2006 Boris Tomic (kodmasin.net)
 * @category 	Kodform
 * @package 	Kodform
 * @author 		Boris Tomic
 * @license 	http://boris.kodmasin.net/kodform4:license The BSD License
 *
 */

require_once "Kodform.php";
require_once 'Kodform/Validator/Required.php';

/**
 * base class for all Kod_Form elements
 */
abstract class Kodform_Element{
	/**
	 * @var Kod_Form holds parent form element
	 */
	protected $form;
	/**
	 * @var array holds list of validators
	 */
	protected $validators;
	/**
	 * @var array holds list of filters
	 */
	protected $filters;
	/**
	 * @var string holds submited (raw) data of element.
	 * 
	 * This variable is only set if form is submited and 
	 * validate method is called (ususaly by parent form in 
	 * isValid). 
	 * Otherwise it holds null 
	 */
	protected $rawValue;
	/**
	 * @var mixed holds value of form which is valid.
	 * 
	 * It is set
	 * if form is submited and value valid (in validate method after
	 * successful validatio). Otherwise it holds null
	 */
	protected $validValue;
	/**
	 * @var mixed this holds default value
	 * 
	 * This value can be set in constructor or vith memeber methods.
	 * It should be used when displaying form only if form is no
	 * submited.
	 */
	protected $defaultValue;
	/**
	 * @var array holds error messages generated by validators
	 * This value is available after calling validate method because
	 * validators are coled there
	 */
	protected $errors;
	/**
	 * @var string holds name of element
	 */
	protected $id;
	/**
	 * @var Required_Validator holds required validator. Element
	 * can have only one validator of this type and it is holded here.
	 */
	protected $required;
	/**
	 * @var string This is display name of this element
	 * 
	 * It is used when comunicating with users (generating errors, ...)
	 */
	protected $displayName;
	/**
	 * creates Kodform_Element element
	 * 
	 * @param string $id name of this element, also used for name 
	 * attribute in html
	 * @param string $defaultValue holds default value of element
	 * @param string $required sets required validator and assign this
	 * string as not valid message   
	 * 
	 */
	function __construct($id, $defaultValue = null, $required = null){
		$this->validators = array();
		$this->filters = array();
		$this->errors = array();
		$this->value = null;
		$this->defaultValue = $defaultValue;
		$this->rawValue = null;
		$this->id = $id;
		$this->form = null;
		$this->required = null;
		if($required != null )
			$this->setRequired($required);
		$this->validValue = null;
		$this->displayName = null;
	}
	/**
	 * sets the parent form
	 */
	function setForm(Kodform &$form){
		$this->form =& $form;
	}
	/**
	 * validate this form element
	 * 
	 * Ususaly called by Kod_Form::isValid
	 * If form is not submite this function alvays returns true.
	 * 
	 * @return boolean if form element valid returns true otherwise false
	 * 
	 */
	function validate(){
		$valid = true;
		//check if form is submited
		if($this->form != null && $this->form->isSubmited()){
			$this->rawValue = $this->form->getRaw($this->id);//get raw submited data
			if($this->required != null){//if required do required validation
				if(!$this->required->validate($this->rawValue)){
					//$valid = false;
					array_push($this->errors, $this->required->getError());
					return false;
				}
			}
			//filter raw data
			$filteredValue = $this->rawValue;
			foreach($this->filters as $filter){
				$filteredValue = $filter->filter($filteredValue);
			}
			//validate with "classic" validators (not required one)
			foreach($this->validators as $validator){
				if(!$validator->validate($filteredValue)){
					$valid = false;
					array_push($this->errors, $validator->getError());
				}
			}
			if($valid)
				$this->validValue = $filteredValue;
		}
		return $valid;
	}
	/**
	 * clears (resets) form value. 
	 * 
	 * Usefull for clearing submited form value
	 */
	function clear(){
		$this->valid = null;
		$this->validValue = null;
	}
	/**
	 * add validator
	 * 
	 * @param Kod_Validator $validator new validator
	 * 
	 * If $validator is of type Required_Validator it will
	 * replace current Required_Validator. SO it is never possible
	 * to have two required validators.
	 */
	function addValidator(Kodform_Validator $validator){
		if($validator instanceof Kodform_Validator_Required)
			$this->required = $validator;
		else
			array_push($this->validators, $validator);
	}
	/**
	 * Add filter
	 * 
	 * Filter difers from validator because it filters value. For example
	 * trim filter removes white space from begining and from the end of string.
	 * After value is filtered it is passed to validators for validation in validate
	 * member function.
	 */
	function addFilter(Kodform_Filter $filter){
		array_push($this->filters, $filter);
	}
	/**
	 * returns validation errors as array
	 * 
	 * @return array 
	 */
	function getErrors(){
		return $this->errors;
	}
	/**
	 * returns Id of element
	 * 
	 * @return string
	 */
	function getId(){
		return $this->id;
	}
	/**
	 * function which is responsible for rendering (displaying) form
	 * element
	 * 
	 * @param Kod_Attributes this element holds attributes ususlay style and class
	 * for diferent element status(error, required, normal, ....)
	 */
	abstract function display(Kodform_Attributes $attributes = null);
	/**
	 * set this element as required
	 * 
	 * @param string $message mesage which will be displayed for validation 
	 * error
	 */
	function setRequired($message){
		$this->required = new Kodform_Validator_Required($message);
	}
	/**
	 * check if element is required
	 */
	function isRequired(){
		if($this->required != null)
			return true;
		return false;
	}
	/**
	 * returns error message which should be used if value for this field
	 * is required
	 * 
	 * @return mixed if it is required than string with message oterwise null
	 */
	function getRequiredError(){
		if($this->required != null)
			return $this->required->getErrors();
		return null;
	}
	/**
	 * check is this field is valid
	 * 
	 * should be used after validate method to get proper results. If not
	 * ti will be always true
	 * 
	 * @return boolean
	 */
	function isValid(){
		$valid = true;
		if(count($this->errors) > 0)
			$valid = false;
		return $valid;
	}
	/**
	 * returns value of this field
	 * 
	 * if form is submited and it is valid you get valid value
	 * if is not valid you get not valid value
	 * if form is not submite you get default value
	 */
	function getValue(){
		$value = $this->defaultValue;
		if($this->form->isSubmited()){
			if($this->isValid())
				$value = $this->validValue;
			else
				$value = $this->form->getRaw($this->id);
		}
		return $value;
	}
	/**
	 * sets display name
	 * 
	 * @param string $name new display name
	 */
	function setDisplayName($name){
		$this->displayName = $name;
	}
	/**
	 * gets display name
	 * 
	 * @return string
	 */
	function getDisplayName(){
		if($this->displayName != null)
			return $this->displayName;
		return $this->id;
	}
	/**
	 * sets default value
	 * 
	 * @param string $value new default value
	 */
	function setDefaultValue($value){
		$this->defaultValue = $value;
	}
}